﻿using Castle.DynamicProxy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using System.Diagnostics;
using Microsoft.AspNetCore.Http;
using Hotel.Repositories;
using Hotel.Domain;
using UAParser;
using Microsoft.AspNetCore.Http.Extensions;
using Newtonsoft.Json;
using SqlSugar;
using Quartz.Impl.AdoJobStore.Common;
using Microsoft.Extensions.Caching.Distributed;
using System.Linq.Expressions;

namespace Hotel.Application
{
    /// <summary>
    /// AOP实现
    /// </summary>
    public class LogInterceptor : Attribute, IInterceptor
    {
        private readonly ILogger<LogInterceptor> logger;
        private readonly IServiceProvider provider;
        private readonly IRepository<OperatorLog> repository;
        private readonly IDistributedCache distributedCache;
        private readonly IRepository<Dic> dicRepository;

        public LogInterceptor(
            ILogger<LogInterceptor> logger,
            IServiceProvider provider,
            IRepository<OperatorLog> repository,
            IDistributedCache distributedCache,
            IRepository<Dic> dicRepository
        )
        {
            this.logger = logger;
            this.provider = provider;
            this.repository = repository;
            this.distributedCache = distributedCache;
            this.dicRepository = dicRepository;

            
        }

        //属性注入
        //public ILogger<LogInterceptor> logger { get; set; }

        public void Intercept(IInvocation invocation)
        {
            OperatorLog operatorLog = new OperatorLog();

            //执行调用的方法  /admin/list?pageindex=1
            invocation.Proceed();

            var httpContext = provider.GetService<IHttpContextAccessor>();


            var context = httpContext.HttpContext;
            if (context != null)
            {
                if (context.User.Identity.IsAuthenticated)
                {
                    operatorLog.UserName = context.User.Identity.Name;
                    operatorLog.Role = "admin";
                }

                //获取用户IP地址
                operatorLog.Ip = context.Connection.RemoteIpAddress.ToString();

                //目标地址
                operatorLog.Location = context.Request.GetDisplayUrl();

                var userAgent = context.Request.Headers["User-Agent"];
                var uaParser = Parser.GetDefault();
                ClientInfo c = uaParser.Parse(userAgent);
                //浏览器
                operatorLog.Browser = $"{c.UA.Family}.{c.UA.Major}.{c.UA.Minor}";
                operatorLog.Os = c.OS.Family;

                //目标类名
                operatorLog.ClassName = invocation.TargetType.Name;
                //目标方法名
                operatorLog.MethodName = invocation.Method.Name;
                //HTTP请求方法
                operatorLog.HttpMthod = context.Request.Method;

                //请求参数
                Dictionary<string, object> dic = new Dictionary<string, object>();
                for (int i = 0; i < invocation.Method.GetParameters().Length; i++)
                {
                    if(invocation.Arguments[i] != null) 
                    { 
                        if (invocation.Arguments[i] is Expression exp)
                        {
                            dic.Add(invocation.Method.GetParameters()[i].Name, exp.ToString());
                        }
                        else
                        {
                            dic.Add(invocation.Method.GetParameters()[i].Name, invocation.Arguments[i]);
                        }
                    }
                }
                operatorLog.RequestParams = JsonConvert.SerializeObject(dic);
                operatorLog.OpTime = DateTime.Now;
                JsonSerializerSettings settings = new JsonSerializerSettings();
                settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

                try
                {
                    if ((invocation.ReturnValue as dynamic).Exception != null)
                    {
                        operatorLog.Result = JsonConvert.SerializeObject((invocation.ReturnValue as dynamic).Exception, settings);
                        operatorLog.Success = false;
                    }
                    else
                    {
                        operatorLog.Result = JsonConvert.SerializeObject((invocation.ReturnValue as dynamic).Result, settings);
                        operatorLog.Success = true;
                    }

                    //过滤掉字典查询的缓存
                    if (!operatorLog.Location.Contains("Dic/QueryByCache"))
                    { 
                        repository.Insert(operatorLog);
                    }
                }
                catch (Exception e)
                {
                    //日志添加失败记录异常日志
                }
            }
        }
    }


}